/*
 * OREKIT-X
 * Copyright 2002-2008 CS Communication & Systemes
 * 
 * Parts of this software package have been licensed to CS
 * Communication & Systemes (CS) under one or more contributor license
 * agreements.  See the NOTICE file distributed with this work for
 * additional information.
 *  
 * This is an experimental copy of OREKIT from www.orekit.org.
 * Please use the original OREKIT from orekit.org for normal work
 * unrelated to this research project.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You
 * may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.  See the License for the specific language governing
 * permissions and limitations under the License.
 */
package ore.time;

import java.io.Serializable;

/** 
 * Date and time components.
 * 
 * Instance of this class are immutable.
 * 
 * @see AbsoluteDate
 * @see DateComponents
 * @see TimeComponents
 * 
 * @author Luc Maisonobe
 */
public class DateTimeComponents
    extends Object
    implements java.lang.Comparable<DateTimeComponents>,
               java.io.Serializable
{

    public final DateComponents date;

    public final TimeComponents time;


    public DateTimeComponents(DateComponents date, TimeComponents time) {
        super();
        this.date = date;
        this.time = time;
    }
    /** 
     * @param year Year number (may be 0 or negative for BC years)
     * @param month Month number from 1 to 12
     * @param day Day number from 1 to 31
     * @param hour Hour number from 0 to 23
     * @param minute Minute number from 0 to 59
     * @param second Second number from 0.0 to 60.0 (excluded)
     * 
     * @exception IllegalArgumentException Parameters out of range
     */
    public DateTimeComponents(int year, int month, int day,
                              int hour, int minute, double second)
        throws IllegalArgumentException
    {
        this ( (new DateComponents(year, month, day)), (new TimeComponents(hour, minute, second)));
    }
    /** 
     * Default hour to 00:00:00.000.
     *
     * @param year Year number (may be 0 or negative for BC years)
     * @param month Month number from 1 to 12
     * @param day Day number from 1 to 31
     * 
     * @exception IllegalArgumentException Parameters out of range
     */
    public DateTimeComponents(int year, int month, int day)
        throws IllegalArgumentException
    {
        this ( (new DateComponents(year, month, day)), TimeComponents.H00);
    }
    /** 
     * @param reference Reference date/time
     * @param offset Offset from the reference in seconds
     * 
     * @see #offsetFrom(DateTimeComponents)
     */
    public DateTimeComponents(DateTimeComponents reference, double offset) {
        super();
        /*
         * Extract linear data from reference date/time
         */
        int    day     = reference.getDate().getJ2000Day();
        double seconds = reference.getTime().getSecondsInDay();
        /*
         * Apply offset
         */
        seconds += offset;
        /*
         * Fix range
         */
        final int dayShift = (int) Math.floor(seconds / 86400.0);
        seconds -= (86400.0 * dayShift);
        day     += dayShift;

        this.date = new DateComponents(day);
        this.time = new TimeComponents(seconds);
    }


    /** 
     * @return Date component
     */
    public DateComponents getDate() {
        return this.date;
    }
    /** 
     * @return Time component
     */
    public TimeComponents getTime() {
        return this.time;
    }
    /** 
     * @param dateTime Subtract from this instance
     * 
     * @return Offset in seconds between the two instants
     * (positive if this instance is later than the argument)
     */
    public double offsetFrom(DateTimeComponents dateTime) {
        int day = (this.date.getJ2000Day() - dateTime.date.getJ2000Day());
        double seconds = (this.time.getSecondsInDay() - dateTime.time.getSecondsInDay());
        return ((86400.0 * day) + seconds);
    }
    public int compareTo(DateTimeComponents that) {
        int comp = this.date.compareTo(that.date);
        if (comp < 0)
            return -1;
        else if (comp > 0)
            return 1;
        else
            return this.time.compareTo(that.time);
    }
    public boolean equals(Object that) {
        if (that instanceof DateTimeComponents){
            DateTimeComponents thatDateTime = (DateTimeComponents) that;
            return (date.equals(thatDateTime.date) && time.equals(thatDateTime.time));
        }
        else
            return false;
    }
    public int hashCode() {
        return ((date.hashCode() << 16) ^ time.hashCode());
    }

    /** 
     * @return ISO-8601 string
     */
    public String toString() {
        return date.toString() + 'T' + time.toString();
    }
}
